///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : "SCL" Safe Code Lib (for C++ unmanaged)
///////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------------------------------------------------
| lock:
| ------------
| Keyword for lock 
---------------------------------------------------------------------------*/
namespace Threading
{
	//
	// IThreadEvent
	//
	struct IThreadEvent : virtual public IObject
	{
		virtual void ReadyForProcessing(void) = 0;
	};

	//
	// TThreadBase
	//

	class TThreadBase : public TObject, virtual public IThreadEvent
	{
		IDKClass;
	public://interface call back
		virtual void OnThreadStart(void){}
		virtual void OnThreadStop(void){}
		virtual void OnThreadLock(void){}
		virtual void ReadyForProcessing(void){}
		virtual bool OnThreadUpdate(float/* dt*/, bool/* ready*/) { return true; }
	};

	class TNonThread : public TThreadBase
	{
		typedef TThreadBase Base;
	protected:
		inline void ThreadStart(void)
		{
			OnThreadStart();
		}

		inline void ThreadSyncExit(void)
		{
			OnThreadStop();
		}

		inline void ThreadLock(void)
		{
			OnThreadLock();
		}

		inline void ThreadUnlock(void)
		{
			//
		}

		void Update(float dt)
		{
			OnThreadUpdate(dt, true);
		}
	};

	class TThread : public TThreadBase
	{
		typedef TThreadBase Base;
	private:
		Platform::Timer mElapsedTime;
		Platform::Event mReadyForProcessing;
		Platform::Event mReadyToSync;
		Platform::Event mWaitToSync;
		bool mThreadStop;
		Platform::ThreadHandle mThreadHandle;
	protected:
		inline void ReadyToSync(void)
		{
			mReadyToSync.Set();
		}
	public:
		inline TThread()
			: mReadyForProcessing(false),
			mReadyToSync(true),
			mWaitToSync(false),
			mThreadStop(false)
		{}

		inline void ThreadLoop()
		{
			OnThreadStart();

			while(OnThreadUpdate(GetElapsedTime(), true))
			{
				//do
			}
		}

		inline void ThreadStart(void)
		{
			mThreadHandle.Create<TThread, &TThread::ThreadLoop>(this);

			ReadyForProcessing();
		}

		inline void ThreadSyncExit(void)
		{
			mThreadStop = true;

			ThreadLock();

			//Clear handle
			mThreadHandle.Close();
		}

	public: // Thread Lock System
		inline void ThreadLock(void)
		{
			ReadyToSync();

			Platform::EventCondition cond;

			cond.Wait(mWaitToSync);
		}

		inline void ThreadUnlock(void)
		{
			ReadyForProcessing();
		}

	public:
		virtual void ReadyForProcessing(void)
		{
			mReadyForProcessing.Set();
		}

		inline float GetElapsedTime(void)
		{
			float elapsed = mElapsedTime.GetElapsed();
			return (elapsed > 1.0f) ? 1.0f : elapsed;
		}

		virtual bool OnThreadUpdate(float, bool ready)
		{
			return Synchronization(ready);
		}

	private:
		//private data
		bool Synchronization(bool ready)
		{
			Platform::EventCondition cond;

			uint eventID = cond.Wait(mReadyToSync, mReadyForProcessing);

			switch(eventID)
			{
			case 0 :
				return OnWaitToSync(ready);

			case 1 :
				if(ready)
				{
					ReadyForProcessing();
				}
				return true;
			}

			return false;
		}

		void WaitToSync(void)
		{
			mReadyToSync.Reset();
			mWaitToSync.Set();
		}

		bool OnWaitToSync(bool ready)
		{
			if(mThreadStop)
			{
				OnThreadStop();
				WaitToSync();
				return false;
			}
			else
			{
				OnThreadLock();
				WaitToSync();
				return Synchronization(ready);
			}
		}
	public:
		void Update(float)
		{
			//do nothing
		}
	};
}
